package com.minis.web.bind.support;

import com.minis.beans.mvc.AbstractPropertyAccessor;
import com.minis.beans.mvc.PropertyEditor;
import com.minis.beans.factory.config.PropertyValue;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 把属性 map 绑定到目标对象
 */
public class BeanWrapperImpl extends AbstractPropertyAccessor {
    // 目标对象
    Object wrappedObject;
    Class<?> clz;

    public BeanWrapperImpl(Object object) {
        // 注册参数转换器
        super();
        this.wrappedObject = object;
        this.clz = object.getClass();
    }

    // 绑定某个具体参数
    @Override
    public void setPropertyValue(PropertyValue pv) {
        // 拿到参数处理器
        BeanPropertyHandler propertyHandler = new BeanPropertyHandler(pv.getName());
        // 找到该参数对应的转换器, 先获取 CustomEditor ，如果它不存在，再获取 DefaultEditor
        PropertyEditor pe = this.getCustomEditor(propertyHandler.getPropertyClz());
        if (pe == null) {
            pe = this.getDefaultEditor(propertyHandler.getPropertyClz());
        }
        // 设置参数值
        pe.setAsText((String) pv.getValue());
        propertyHandler.setValue(pe.getValue());

    }

    // 一个内部类，用于处理参数，通过getter()和setter()操作属性
    class BeanPropertyHandler {
        Method writeMethod = null;
        Method readMethod = null;
        Class<?> propertyClz = null;

        public Class<?> getPropertyClz() {
            return propertyClz;
        }

        public BeanPropertyHandler(String propertyName) {
            try {
                Field field = clz.getDeclaredField(propertyName);
                propertyClz = field.getType();
                System.out.println(clz.toString());
                this.writeMethod = clz.getDeclaredMethod("set"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1),propertyClz);
                this.readMethod = clz.getDeclaredMethod("get"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1));
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        public Object getValue() {
            Object result = null;
            readMethod.setAccessible(true);

            try {
                result =  readMethod.invoke(wrappedObject);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return result;

        }

        public void setValue(Object value) {
            writeMethod.setAccessible(true);
            try {
                writeMethod.invoke(wrappedObject, value);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

    }

}
